package com.canaan.business.service.bill.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.canaan.business.common.enums.basic.YNEnum;
import com.canaan.business.common.enums.inOutStock.OutOrderStatusEnum;
import com.canaan.business.common.enums.inOutStock.OutStockOrderTypeEnum;
import com.canaan.business.domain.basic.WmsProduct;
import com.canaan.business.domain.basic.WmsStorehouse;
import com.canaan.business.domain.bill.PickProductBill;
import com.canaan.business.domain.bill.PickProductBillDetail;
import com.canaan.business.domain.inOutStock.WmsOutStockOrder;
import com.canaan.business.domain.storehouse.WmsStorehouseStock;
import com.canaan.business.domain.vo.PickProductBillExportVo;
import com.canaan.business.domain.vo.StockDetailProductVo;
import com.canaan.business.mapper.bill.PickProductBillMapper;
import com.canaan.business.service.basic.IWmsProductService;
import com.canaan.business.service.basic.IWmsStorehouseService;
import com.canaan.business.service.bill.IPickProductBillDetailService;
import com.canaan.business.service.bill.IPickProductBillService;
import com.canaan.business.service.inOutStock.IWmsOutStockDetailOrderService;
import com.canaan.business.service.inOutStock.IWmsOutStockOrderService;
import com.canaan.business.service.storehouse.IWmsStorehouseStockService;
import com.canaan.common.constant.PrefixConstants;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import com.canaan.common.utils.StringUtils;
import com.canaan.common.utils.TableNoUtil;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 领料单Service业务层处理
 *
 * @author ruoyi
 * @date 2023-01-30
 */
@Service
public class PickProductBillServiceImpl implements IPickProductBillService {
    @Resource
    private PickProductBillMapper pickProductBillMapper;
    @Resource
    private IWmsOutStockOrderService wmsOutStockOrderService;
    @Resource
    private IWmsOutStockDetailOrderService wmsOutStockDetailOrderService;
    @Resource
    private IWmsStorehouseService storehouseService;
    @Resource
    private IPickProductBillService pickProductBillService;
    @Resource
    private IPickProductBillDetailService pickProductBillDetailService;
    @Resource
    private IWmsProductService productService;
    @Resource
    private IWmsStorehouseStockService wmsStorehouseStockService;

    /**
     * 查询领料单
     *
     * @param id 领料单主键
     * @return 领料单
     */
    @Override
    public PickProductBill selectPickProductBillById(Long id) {
        return pickProductBillMapper.selectPickProductBillById(id);
    }

    /**
     * 查询领料单列表
     *
     * @param pickProductBill 领料单
     * @return 领料单
     */
    @Override
    public List<PickProductBill> selectPickProductBillList(PickProductBill pickProductBill) {
        return pickProductBillMapper.selectPickProductBillList(pickProductBill);
    }

    /**
     * 新增领料单
     *
     * @param pickProductBill 领料单
     * @return 结果
     */
    @Override
    public int insertPickProductBill(PickProductBill pickProductBill) {
        if(pickProductBill==null){
            throw new ServiceException("数据对象为空");
        }
        if (StringUtils.isEmpty(pickProductBill.getStorehouseNo())){
            throw new ServiceException("仓库不能为空");
        }
        if (StringUtils.isBlank(pickProductBill.getNo())) {
            pickProductBill.setNo(PrefixConstants.PICK_PRODUCT+TableNoUtil.getNo(PickProductBill.class));
        }
        if(YNEnum.Y.getCode().equals(pickProductBill.getWhetherMp())){
            if (StringUtils.isEmpty(pickProductBill.getWorkOrderNo())){
                throw new ServiceException("当已备料时，工单编号不能为空");
            }
        }
        pickProductBill.setCreateBy(SecurityUtils.getUsername());
        pickProductBill.setCreateTime(DateUtils.getNowDate());
        pickProductBill.setStatus(OutOrderStatusEnum.NEW.getCode());
        if (CollUtil.isNotEmpty(pickProductBill.getPickProductBillDetailList())) {
            //生成物料清单
            pickProductBill.setTotalQty(pickProductBill.getPickProductBillDetailList().stream().filter(e->e.getQty()!=null).mapToLong(e -> e.getQty()).sum());
            pickProductBill.getPickProductBillDetailList().forEach(e -> e.setBillNo(pickProductBill.getNo()));
            this.pickProductBillDetailService.batchInsertPickProductBillDetail(pickProductBill.getPickProductBillDetailList());
        }
//        //生成领料出库单
//        WmsOutStockOrder wmsOutStockOrder = new WmsOutStockOrder();
//        wmsOutStockOrder.setOrderType(InOutStockTypeEnum.PICK_OUT.getCode());
//        wmsOutStockOrder.setOrderStatus(OrderStatusEnum.NEW.getCode());
//        wmsOutStockOrderService.insertWmsOutStockOrder(wmsOutStockOrder);
        return pickProductBillMapper.insertPickProductBill(pickProductBill);
    }

    /**
     * 批量新增领料单
     *
     * @param pickProductBillList 领料单列表
     * @return 结果
     */
    @Override
    public int batchInsertPickProductBill(List<PickProductBill> pickProductBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (PickProductBill pickProductBill : pickProductBillList) {
            if (StringUtils.isBlank(pickProductBill.getNo())) {
                pickProductBill.setNo(TableNoUtil.getNo(PickProductBill.class));
            }
            pickProductBill.setCreateBy(username);
            pickProductBill.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i = 0; i < pickProductBillList.size(); ) {
            int endIndex = i + 500;
            if (endIndex > pickProductBillList.size()) {
                endIndex = pickProductBillList.size();
            }
            insertNum = insertNum + pickProductBillMapper.batchInsertPickProductBill(pickProductBillList.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }

    /**
     * 修改领料单
     *
     * @param pickProductBill 领料单
     * @return 结果
     */
    @Override
    public int updatePickProductBill(PickProductBill pickProductBill) {
        pickProductBill.setUpdateBy(SecurityUtils.getUsername());
        pickProductBill.setUpdateTime(DateUtils.getNowDate());
        return pickProductBillMapper.updatePickProductBill(pickProductBill);
    }

    /**
     * 批量修改领料单
     *
     * @param pickProductBillList 领料单列表
     * @return 结果
     */
    @Override
    public int batchUpdatePickProductBill(List<PickProductBill> pickProductBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (PickProductBill pickProductBill : pickProductBillList) {
            pickProductBill.setUpdateBy(username);
            pickProductBill.setUpdateTime(currerTime);
        }
        int updateNum = 0;
        for (int i = 0; i < pickProductBillList.size(); ) {
            int endIndex = i + 500;
            if (endIndex > pickProductBillList.size()) {
                endIndex = pickProductBillList.size();
            }
            updateNum = updateNum + pickProductBillMapper.batchUpdatePickProductBill(pickProductBillList.subList(i, endIndex));
            i = endIndex;
        }
        return updateNum;
    }

    /**
     * 批量删除领料单
     *
     * @param ids 需要删除的领料单主键集合
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deletePickProductBillByIds(Long[] ids) {
        PickProductBill bill = new PickProductBill();
        bill.setIds(CollUtil.toList(ids));
        List<PickProductBill> billList = this.selectPickProductBillList(bill);
        List<String> nos = billList.stream()
                .filter(e -> OutOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode().equals(e.getStatus())
                        || OutOrderStatusEnum.ACCOMPLISH.getCode().equals(e.getStatus()))
                .map(PickProductBill::getNo).collect(Collectors.toList());
        if(!nos.isEmpty()){
            throw new ServiceException("取消待确认或已完成状态的单据不能删除");
        }
        for (PickProductBill productBill : billList) {
            if(OutOrderStatusEnum.PICKING.getCode().equals(productBill.getStatus())){
                //校验进行中单据下的出入库单数据
                WmsOutStockOrder stockOrder = wmsOutStockOrderService.selectWmsOutStockOrderByRelOrderNo(productBill.getNo(), OutStockOrderTypeEnum.PICK.getCode());
                if(stockOrder != null && stockOrder.getTotalActualQty() > 0){
                    nos.add(productBill.getNo());
                }
            }
        }
        if(!nos.isEmpty()){
            throw new ServiceException(nos + "单据已有实际出库数量不能删除");
        }
        //出库单和出库单明细删除
        nos = billList.stream().map(PickProductBill::getNo).collect(Collectors.toList());
        wmsOutStockOrderService.deleteWmsOutStockOrderByRelOrderNosAndType(nos, OutStockOrderTypeEnum.PICK.getCode());
        return pickProductBillMapper.deletePickProductBillByIds(ids);
    }

    /**
     * 删除领料单信息
     *
     * @param id 领料单主键
     * @return 结果
     */
    @Override
    public int deletePickProductBillById(Long id) {
        return pickProductBillMapper.deletePickProductBillById(id);
    }

    /**
     * 查询领料单
     *
     * @param no 编号
     * @return 领料单
     */
    @Override
    public PickProductBill selectPickProductBillByNo(String no) {
        return pickProductBillMapper.selectPickProductBillByNo(no);
    }

    /**
     * 批量删除领料单
     *
     * @param nos 需要删除的编号集合
     * @return 结果
     */
    @Override
    public int deletePickProductBillByNos(String[] nos) {
        return pickProductBillMapper.deletePickProductBillByNos(nos);
    }

    /**
     * 删除领料单信息
     *
     * @param no 编号
     * @return 结果
     */
    @Override
    public int deletePickProductBillByNo(String no) {
        return pickProductBillMapper.deletePickProductBillByNo(no);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int confirm(List<Long> ids) {
        PickProductBill bill = new PickProductBill();
        bill.setIds(ids);
        List<PickProductBill> billList = this.selectPickProductBillList(bill);
        billList = billList.stream().filter(e -> OutOrderStatusEnum.NEW.getCode().equals(e.getStatus())).collect(Collectors.toList());
        if (billList.isEmpty()) {
            return 0;
        }
        for (PickProductBill pickProductBill : billList) {
            if (StringUtils.isNotEmpty(pickProductBill.getWhetherMp())){
                if(YNEnum.Y.getCode().equals(pickProductBill.getWhetherMp())){
                    if (StringUtils.isEmpty(pickProductBill.getWorkOrderNo())){
                        throw new ServiceException("如果已备料，工单编号不能为空");
                    }
                }
            }
            pickProductBill.setStatus(OutOrderStatusEnum.PICKING.getCode());
        }
        this.batchUpdatePickProductBill(billList);

        //添加出库单
        for (PickProductBill pickProductBill : billList) {
            PickProductBillDetail pickProductBillDetail = new PickProductBillDetail();
            pickProductBillDetail.setBillNo(pickProductBill.getNo());
            List<PickProductBillDetail> billDetails = this.pickProductBillDetailService.selectPickProductBillDetailList(pickProductBillDetail);
            if (CollUtil.isEmpty(billDetails)) {
                throw new ServiceException("未维护明细数据");
            }
            if (YNEnum.Y.getCode().equals(pickProductBill.getWhetherMp())){
                 if (StringUtils.isNotEmpty(pickProductBill.getWorkOrderNo())){
                     //查询备料区库存是否已完成备料
                     for (PickProductBillDetail billDetail : billDetails) {
                        List<WmsStorehouseStock> list = this.wmsStorehouseStockService.selectMpByWorkOrderNoAndProductNo(YNEnum.Y.getCode(),pickProductBill.getWorkOrderNo(),billDetail.getProductNo());
                        if (CollectionUtil.isEmpty(list)){
                            throw new ServiceException("物料编号："+billDetail.getProductNo()+"还未完成备料，请先完成备料");
                        }else{
                            long qty = list.stream().mapToLong(WmsStorehouseStock::getQty).sum();
                            if (billDetail.getQty()>qty){
                                throw new ServiceException("物料编号："+billDetail.getProductNo()+"还未完成备料，请先完成备料");
                            }
                        }
                     }
                 }
            }
            List<StockDetailProductVo> stockDetailProductVos = new ArrayList<>();
            for (PickProductBillDetail billDetail : billDetails) {
                StockDetailProductVo detailProductVo = new StockDetailProductVo();
                detailProductVo.setProductNo(billDetail.getProductNo());
                detailProductVo.setOrderQty(billDetail.getQty());
                stockDetailProductVos.add(detailProductVo);
            }
            wmsOutStockOrderService.initBillStockOrder(pickProductBill.getNo(), OutStockOrderTypeEnum.PICK.getCode(), stockDetailProductVos,"",pickProductBill.getWorkOrderNo());
        }

        return billList.size();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int complete(List<Long> ids) {
        PickProductBill bill = new PickProductBill();
        bill.setIds(ids);
        List<PickProductBill> billList = this.selectPickProductBillList(bill);
        billList = billList.stream().filter(e -> OutOrderStatusEnum.PICKING.getCode().equals(e.getStatus())).collect(Collectors.toList());
        if (billList.isEmpty()) {
            throw  new ServiceException("单据状态不是"+OutOrderStatusEnum.PICKING.getMessage());
        }
        String username = SecurityUtils.getUsername();
        Date date = DateUtils.getNowDate();
        for (PickProductBill pickProductBill : billList) {
            WmsOutStockOrder wmsOutStockOrder = wmsOutStockOrderService.selectWmsOutStockOrderByRelOrderNo(pickProductBill.getNo(), OutStockOrderTypeEnum.PICK.getCode());
            if (wmsOutStockOrder != null && OutOrderStatusEnum.ACCOMPLISH.getCode().equals(wmsOutStockOrder.getOrderStatus())) {
                pickProductBill.setUpdateBy(username);
                pickProductBill.setUpdateTime(date);
                pickProductBill.setCompleteTime(date);
                pickProductBill.setStatus(OutOrderStatusEnum.ACCOMPLISH.getCode());
            } else {
                throw new ServiceException("出库单未完成，关联编号：" + wmsOutStockOrder.getNo());
            }
        }
        pickProductBillMapper.batchUpdatePickProductBill(billList);
        return 1;
    }

    @Override
    public List<PickProductBillExportVo> exportList(PickProductBill pickProductBill) {
        return pickProductBillMapper.exportList(pickProductBill);
    }

    @Override
    public List<String> importExcel(List<PickProductBillExportVo> list) {
        List<String> errList = new ArrayList<>();
        Map<String, List<PickProductBillExportVo>> groupMap = list.stream().collect(Collectors.groupingBy(PickProductBillExportVo::getStorehouseName));
        Set<String> storehouseNames = groupMap.keySet();
        for (String storehouseName : storehouseNames) {
            List<PickProductBillExportVo> pickProductBillVos = groupMap.get(storehouseName);
            WmsStorehouse wmsStorehouse = storehouseService.selectWmsStorehouseByName(storehouseName);
            if (wmsStorehouse == null) {
                errList.add("无效仓库名称：" + storehouseName);
                continue;
            }
            PickProductBill pickProductBill = new PickProductBill();
            pickProductBill.setStorehouseNo(wmsStorehouse.getNo());
            pickProductBill.setStorehouseName(wmsStorehouse.getName());
            pickProductBill.setTotalQty(pickProductBillVos.stream().filter(e->e.getQty()!=null).mapToLong(e -> e.getQty()).sum());
            pickProductBillService.insertPickProductBill(pickProductBill);

            List<PickProductBillDetail> details = new ArrayList<>();
            for (PickProductBillExportVo pickProductBillVo : pickProductBillVos) {
                PickProductBillDetail pickProductBillDetail = new PickProductBillDetail();
                pickProductBillDetail.setBillNo(pickProductBill.getNo());
                pickProductBillDetail.setQty(pickProductBillVo.getQty());
                pickProductBillDetail.setProductNo(pickProductBillVo.getProductNo());
                WmsProduct wmsProduct = productService.selectWmsProductByProductNo(pickProductBillVo.getProductNo());
                if (wmsProduct == null) {
                    errList.add("无效物料编码：" + pickProductBillVo.getProductNo());
                    continue;
                }
                pickProductBillDetail.setProductName(wmsProduct.getProductName());
                pickProductBillDetail.setProductUnit(wmsProduct.getCompany());
                details.add(pickProductBillDetail);
            }
            if (CollUtil.isNotEmpty(details)) {
                pickProductBillDetailService.batchInsertPickProductBillDetail(details);
            }
        }
        return errList;
    }

    @Override
    @Transactional
    public int cancel(List<Long> ids) {
        PickProductBill bill = new PickProductBill();
        bill.setIds(ids);
        List<PickProductBill> billList = this.selectPickProductBillList(bill);
        billList = billList.stream().filter(e -> OutOrderStatusEnum.NEW.getCode().equals(e.getStatus())
                || OutOrderStatusEnum.PICKING.getCode().equals(e.getStatus())).collect(Collectors.toList());
        if (billList.isEmpty()) {
            return 0;
        }
        for (PickProductBill pickProductBill : billList) {
            WmsOutStockOrder wmsOutStockOrder = wmsOutStockOrderService.selectWmsOutStockOrderByRelOrderNo(pickProductBill.getNo(), OutStockOrderTypeEnum.PICK.getCode());
            if (wmsOutStockOrder != null) {
                if (wmsOutStockOrder.getTotalActualQty() > 0) {
                    throw new ServiceException("已出库不允许取消，单号：" + pickProductBill.getNo());
                }
                wmsOutStockOrder.setOrderStatus(OutOrderStatusEnum.CANCEL.getCode());
                this.wmsOutStockOrderService.updateWmsOutStockOrder(wmsOutStockOrder);
            }
        }
        billList.stream().forEach(e -> e.setStatus(OutOrderStatusEnum.CANCEL.getCode()));
        this.batchUpdatePickProductBill(billList);
        return billList.size();
    }

    /**
     * 确认取消
     * @param bill 单据信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int confirmCancel(PickProductBill bill) {
        bill = this.selectPickProductBillById(bill.getId());
        if(bill == null){
            throw new ServiceException("单据不存在");
        }else if(!OutOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode().equals(bill.getStatus())){
            throw new ServiceException("该状态不是取消待确认，无法确认取消");
        }

        WmsOutStockOrder stockOrder = wmsOutStockOrderService.selectWmsOutStockOrderByRelOrderNo(bill.getNo(), OutStockOrderTypeEnum.PICK.getCode());
        if(stockOrder != null){
            stockOrder.setOrderStatus(OutOrderStatusEnum.CANCEL.getCode());
            wmsOutStockOrderService.updateWmsOutStockOrder(stockOrder);
        }
        bill.setStatus(OutOrderStatusEnum.CANCEL.getCode());
        return this.updatePickProductBill(bill);
    }
}
